package com.liting.uitest.imgutils;

import java.io.ByteArrayInputStream;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.commons.codec.binary.Base64;

//import gui.ava.html.image.generator.HtmlImageGenerator;

/**
 * 图片处理
 *
 * @author tb
 */
public class ImgTools {
    /**
     * 裁剪图片-优化版本；以图片中心为源点，按照长宽比进行图片裁剪，裁剪圆形
     *
     * @param bi
     * @param widthToHeight 长宽比例，若是为1则是圆形
     * @return BufferedImage
     * @throws IOException
     */
    public static BufferedImage cutPicArc(BufferedImage bi, float widthToHeight) throws IOException {
        int width = bi.getWidth();
        int height = bi.getHeight();

        int dw = 0;
        int dh = 0;
        if (width / (height * 1.0) > widthToHeight) {//截长
            dw = Math.round(Math.abs(width - widthToHeight * height));
        } else {//截高
            dh = Math.round(Math.abs(height - (1 / widthToHeight) * width));
        }

        BufferedImage bi2 = new BufferedImage(width - dw, height - dh, Transparency.TRANSLUCENT);
        Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, width - dw, height - dh);

        Graphics2D g2 = bi2.createGraphics();
        g2.setClip(shape);
        // 使用 setRenderingHint 设置抗锯齿
        g2.drawImage(bi, 0, 0, null);
        g2.dispose();
        return bi2;
    }

    /**
     * 裁剪图片-优化版本；以图片中心为源点，按照长宽比进行图片裁剪，裁剪矩形
     *
     * @param bi
     * @param widthToHeight 长宽比例，若是为1则是正方形
     * @return BufferedImage
     * @throws IOException
     */
    public static BufferedImage cutPicRect(BufferedImage bi, float widthToHeight) throws IOException {
        int width = bi.getWidth();
        int height = bi.getHeight();

        int dw = 0;
        int dh = 0;
        if (width / (height * 1.0) > widthToHeight) {//截长
            dw = Math.round(Math.abs(width - widthToHeight * height));
        } else {//截高
            dh = Math.round(Math.abs(height - (1 / widthToHeight) * width));
        }

        BufferedImage bi2 = new BufferedImage(width - dw, height - dh, Transparency.TRANSLUCENT);
        Graphics2D g2 = bi2.createGraphics();
        // 使用 setRenderingHint 设置抗锯齿
        g2.drawImage(bi, -dw / 2, -dh / 2, null);
        g2.dispose();
        return bi2;
    }

    /**
     * 缩放图片
     *
     * @param bi
     * @param scale 比例饿
     * @return BufferedImage
     */
    public static BufferedImage humbnailPic(BufferedImage bi, float scale) throws IOException {
        int width = bi.getWidth();
        int height = bi.getHeight();

        BufferedImage bi2 = new BufferedImage(Math.round(width * scale), Math.round(height * scale), Transparency.TRANSLUCENT);

        Graphics2D g2 = bi2.createGraphics();
        // 使用 setRenderingHint 设置抗锯齿
        g2.drawImage(bi, 0, 0, Math.round(width * scale), Math.round(height * scale), 0, 0, width, height, null);
        g2.dispose();
        return bi2;
    }

    /**
     * 缩放图片-按最小长宽进行压缩
     *
     * @param bi
     * @param minWidth
     * @param minHeight
     * @return BufferedImage
     */
    public static BufferedImage humbnailPicMin(BufferedImage bi, int minWidth, int minHeight) throws IOException {
        int width = bi.getWidth();
        int height = bi.getHeight();

        float scale = 0f;

        if (minWidth / width > minHeight / height) {//取小比例

            scale = 1.0f * minHeight / height;

        } else scale = 1.0f * minWidth / width;

        BufferedImage bi2 = new BufferedImage(Math.round(width * scale), Math.round(height * scale), Transparency.TRANSLUCENT);

        Graphics2D g2 = bi2.createGraphics();
        // 使用 setRenderingHint 设置抗锯齿
        g2.drawImage(bi, 0, 0, Math.round(width * scale), Math.round(height * scale), 0, 0, width, height, null);
        g2.dispose();
        return bi2;
    }

    /**
     * 多张图片合成为一张图-竖向
     *
     * @param imagePaths  图片路径数组
     * @param width       合成后图片宽度
     * @param widthFixing 是否固宽（固宽即是所有的图片的宽度一致，大于此宽度的等比例压缩，小于的等比例扩大）
     * @return
     */
    public static BufferedImage composeImageVertical(String[] imagePaths, int width) {

        File[] files = new File[imagePaths.length];

        for (int index = 0; index < files.length; index++) {

            files[index] = new File(imagePaths[index]);

        }

        return composeImageVertical(files, width);
    }

    /**
     * 目录下所有图片合成为一张图-竖向
     *
     * @param imagePaths  图片路径数组
     * @param width       合成后图片宽度
     * @param widthFixing 是否固宽（固宽即是所有的图片的宽度一致，大于此宽度的等比例压缩，小于的等比例扩大）
     * @return
     */
    public static BufferedImage composeImageVertical(String imageDir, int width) {

        File[] files = new File(imageDir).listFiles();

        return composeImageVertical(files, width);
    }

    /**
     * 多张图片合成为一张图-竖向
     *
     * @param images
     * @param width  合成后图片宽度
     * @return
     */
    public static BufferedImage composeImageVertical(File[] images, int width) {

        //计算所有的图片合起来的高度
        BufferedImage[] bufferedImages = new BufferedImage[images.length];//处理后的图片
        int height = 0;
        for (int index = 0; index < images.length; index++) {

            File image = images[index];
            try {

                BufferedImage bImage = ImageIO.read(image);
                //按宽度进行原图片等比缩放
                int newWidth = bImage.getWidth();
                float scale = width * 1.0f / newWidth;
                bImage = humbnailPic(bImage, scale);
                height += bImage.getHeight();
                bufferedImages[index] = bImage;

            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }

        }
        //构建目标图片
        BufferedImage bi2 = new BufferedImage(width, height, Transparency.TRANSLUCENT);

        Graphics2D g2 = bi2.createGraphics();
        int finishHeight = 0;//已经完成的高，用于定位下一张图片的起始位置
        //将所有图片画于目标图片上
        for (int index = 0; index < bufferedImages.length; index++) {

            BufferedImage bufferedImage = bufferedImages[index];

            g2.drawImage(bufferedImage, 0, finishHeight, width, bufferedImage.getHeight(), null);

            finishHeight += bufferedImage.getHeight();
        }
        g2.dispose();
        return bi2;
    }

    /**
     * 创建绘图对象
     *
     * @param width  宽度
     * @param height 高度
     * @param color  背景颜色
     * @return
     */
    public static BufferedImage createImage(int width, int height, Color color) {

        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = bi.getGraphics();
        if (color != null) {
            g.setColor(color);
            g.fillRect(0, 0, width, height);
        }

        return bi;
    }

    /**
     * 画边框
     *
     * @param bi
     * @param borderSize  边框宽度
     * @param borderColor 边框颜色
     * @return
     */
    public static BufferedImage drawBorder(BufferedImage bi, float borderSize, Color borderColor) {

        int width = bi.getWidth();
        int height = bi.getHeight();
        Graphics2D g = bi.createGraphics();
        g.setStroke(new BasicStroke(borderSize));
        g.setColor(borderColor == null ? Color.GRAY : borderColor);
        g.drawLine(0, 0, width, 0);
        g.drawLine(width - 2, 0, width - 2, height);
        g.drawLine(width, height - 1, 0, height - 1);
        g.drawLine(0, height, 0, 0);
        g.dispose();

        return bi;
    }

    /**
     * 水印
     *
     * @param bi
     * @param str   水印字符串
     * @param color 水印颜色
     * @param size  字体大小
     * @param hDis  高间隔
     * @param yDis  宽间隔
     * @return
     */
    public static BufferedImage watermark(BufferedImage bi, String str, Color color, int size, int hDis, int yDis) {

        int len = str.length();
        Graphics2D g = bi.createGraphics();
        g.translate(0, 0);
        g.rotate(-Math.PI / 4);
        g.setColor(color);
        g.setFont(new Font("Fixedsys", Font.PLAIN, size));
        for (int py = 0; py <= 2 * bi.getHeight(); py += hDis) {

            for (int px = -bi.getWidth() / 2; px <= bi.getWidth() / 2; px += len * 20 + yDis) {

                g.drawString(str, px, py);

            }


        }
        g.dispose();

        return bi;
    }

    /**
     * 写字
     *
     * @param bi     BufferedImage
     * @param text   文本
     * @param color  Color.green
     * @param pointX 起点的x坐标
     * @param pointY 起点的y坐标
     * @param size   字体大小
     * @return
     */
    public static BufferedImage drawFont(BufferedImage bi, String text, Color color, int pointX, int pointY, int size) {

        //g.setColor(Color.green);
        Graphics2D g = bi.createGraphics();
        g.setColor(color);
        g.setFont(new Font("Fixedsys", Font.PLAIN, size));
        g.drawString(text, pointX, pointY);
        g.dispose();

        return bi;
    }

    /**
     * 插入图片
     *
     * @param g      Graphics
     * @param image  图片文件file
     * @param pointX 起点x坐标
     * @param pointY 起点y坐标
     * @param width  自定义插入图片的宽度（高度按比例缩放），若是为0则表示原图片的宽高
     * @return
     * @throws IOException
     */
    public static BufferedImage drawImage(BufferedImage bi, File image, int pointX, int pointY, int width) throws IOException {

        //g.setColor(Color.green);
        Graphics2D g = bi.createGraphics();
        BufferedImage bufferedImage = ImageIO.read(image);
        int sWidth = bufferedImage.getWidth();
        int sHeight = bufferedImage.getHeight();
        if (width != 0) {
            //按比例计算图片的高度
            sHeight = Integer.valueOf(String.valueOf(Math.round((width * 1.0 / sWidth) * sHeight)));
            sWidth = width;
        }

        g.drawImage(bufferedImage, pointX, pointY, sWidth, sHeight, null);
        g.dispose();
        return bi;
    }

    /**
     * 插入图片
     *
     * @param bi            BufferedImage
     * @param BufferedImage
     * @param pointX        起点x坐标
     * @param pointY        起点y坐标
     * @param width         自定义插入图片的宽度（高度按比例缩放），若是为0则表示原图片的宽高
     * @return
     * @throws IOException
     */
    public static BufferedImage drawImage(BufferedImage bi, BufferedImage bufferedImage, int pointX, int pointY, int width) throws IOException {

        //g.setColor(Color.green);
        Graphics2D g = bi.createGraphics();
        int sWidth = bufferedImage.getWidth();
        int sHeight = bufferedImage.getHeight();
        if (width != 0) {
            //按比例计算图片的高度
            sHeight = Integer.valueOf(String.valueOf(Math.round((width * 1.0 / sWidth) * sHeight)));
            sWidth = width;
        }

        g.drawImage(bufferedImage, pointX, pointY, sWidth, sHeight, null);
        g.dispose();
        return bi;
    }

    /**
     * 画正玄曲线 横向的
     * 注：内嵌了随机颜色生成，故而产生的线是多彩色
     *
     * @param g      graphics
     * @param width  img'width
     * @param height img'height
     * @param r      周期半径
     * @param f      峰度
     * @return graphics
     */
    public static BufferedImage drawCurve(BufferedImage bi, int x1, int y1, Integer x2, Integer y2, int r, int f) {

        Graphics2D g = bi.createGraphics();

        int disX = x2 - x1;
        int disY = y2 - y1;
        double yd = y1;
        for (int j = 1; j <= disX; j++) {
            x2 = x1 + 1;
            if (disY != 0) {
                yd = disY * 1.0 / disX * 1 + y1;
            }

            y2 = (int) Math.round(Math.sin(x2 / r) * f + yd);
            setRandomColor(g);
            g.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }
        g.dispose();
        return bi;
    }

    /**
     * 画正玄曲线 纵向的
     * 注：内嵌了随机颜色生成，故而产生的线是多彩色
     *
     * @param g      graphics
     * @param width  img'width
     * @param height img'height
     * @param r      周期半径
     * @param f      峰度
     * @return graphics
     */
    public static BufferedImage drawCurveH(BufferedImage bi, int width, int height, int r, int f) {

        Graphics2D g = bi.createGraphics();
        int xD = (int) Math.round(Math.random() * width);
        int x1 = xD;
        int y1 = 0;
        int y2 = 0;
        int x2 = 0;
        for (int j = 0; j < height; j++) {
            y2 = y1 + 1;
            setRandomColor(g);
            x2 = (int) Math.round(Math.sin(y2 / r) * f) + xD;
            g.drawLine(x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
        }

        g.dispose();
        return bi;
    }

    /**
     * 画圆，其实上是画椭圆，如果横半径与纵半径相等则是特殊的椭圆-->圆
     *
     * @param g      graphics
     * @param wR     横半径
     * @param hR     纵半径
     * @param startW 开始角度
     * @param endW   结束角度
     *               注:角度均是0到360
     * @return
     */
    public static BufferedImage drawCirCle(BufferedImage bi, int wR, int hR, int startW, int endW) {

        Graphics2D g = bi.createGraphics();

        setRandomColor(g);
        g.drawArc(0, 0, wR, hR, startW, endW);
        //画椭圆的，不过感觉是多余的
        //g.drawOval(0, 0, wR, hR);
        g.dispose();
        return bi;
    }

    /**
     * 自带的画圆很有局限性，该方法可以将圆设置为多彩色
     * 注：内嵌了随机颜色生成，故而产生的线是多彩色
     *
     * @param g   graphics
     * @param xDs 圆心的x坐标
     * @param yDs 圆心的y坐标
     * @param r   该圆的半径
     * @return graphics
     */
    public static BufferedImage drawCirCleByMine(BufferedImage bi, int xDs, int yDs, int r) {
        Graphics2D g = bi.createGraphics();
        int yD = yDs;
        int xD = xDs - 20;
        int y1 = yD;
        int x1 = 0;
        int x2 = 0;
        int y2 = 0;
        for (int j = 0; j <= r * 2; j++) {
            x2 = x1 + 1;
            y2 = (int) Math.round(Math.sqrt(r * r - (x2 - r) * (x2 - r))) + yD;
            setRandomColor(g);
            g.drawLine(x1 + xD, y1, x2 + xD, y2);
            x1 = x2;
            y1 = y2;
        }
        x1 = 0;
        y1 = yD;
        for (int j = 0; j <= r * 2; j++) {
            x2 = x1 + 1;
            y2 = yD - (int) Math.round(Math.sqrt(r * r - (x2 - r) * (x2 - r)));
            setRandomColor(g);
            g.drawLine(x1 + xD, y1, x2 + xD, y2);
            x1 = x2;
            y1 = y2;
        }

        g.dispose();

        return bi;
    }

    /**
     * 设置随机颜色
     *
     * @param g
     * @return
     */
    public static Graphics setRandomColor(Graphics g) {
        int red = 0;
        int green = 0;
        int blue = 0;
        Random random = new Random();
        // 产生随机的颜色分量来构造颜色值，这样输出的每位数字的颜色值都将不同。
        red = random.nextInt(255);
        green = random.nextInt(255);
        blue = random.nextInt(255);
        // 用随机产生的颜色将验证码绘制到图像中。
        g.setColor(new Color(red, green, blue));
        return g;
    }
    /**
     * html格式文本转换成图片
     * @param htmlStr
     * @return
     */
//    public static BufferedImage html2image(String htmlStr) {
//
//        HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
//
//        imageGenerator.loadHtml(htmlStr);
//
//        BufferedImage bufferedImage = imageGenerator.getBufferedImage();
//
//        return bufferedImage;
//    }

    /**
     * 画线-实线
     *
     * @param bi
     * @param x1    起点x坐标
     * @param y1    起点y坐标
     * @param x2    终点x坐标
     * @param y2    终点y坐标
     * @param color 颜色
     * @param size  粗细
     * @return
     */
    public static BufferedImage drawLine(BufferedImage bi, int x1, int y1, int x2, int y2, Color color, float size) {

        Graphics2D g = bi.createGraphics();
        g.setColor(color);
        g.setStroke(new BasicStroke(size));
        g.drawLine(x1, y1, x2, y2);
        g.dispose();


        return bi;
    }

    /**
     * 转base64String
     *
     * @return 失败返回null
     */
    public static String toBase64(BufferedImage bi) {

        //转为base64
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bi, "jpg", outputStream);
        } catch (IOException e) {

            return null;

        }
        byte[] bytes = outputStream.toByteArray();
        String base64String = Base64.encodeBase64String(bytes);

        return "data:image/png;base64," + base64String;
    }

    /**
     * 画线-虚线
     *
     * @param bi
     * @param x1       起点x坐标
     * @param y1       起点y坐标
     * @param x2       终点x坐标
     * @param y2       终点y坐标
     * @param color    颜色
     * @param size     粗细
     * @param lineSize 线段长度
     * @param disSize  间隔长度
     * @return
     */
    public static BufferedImage drawLine(BufferedImage bi, int x1, int y1, int x2, int y2, Color color, float size, int lineLen, int disLen) {

        Graphics2D g = bi.createGraphics();
        g.setColor(color);
        g.setStroke(new BasicStroke(size));

        int lenX = x2 - x1;
        int lenY = y2 - y1;

        if (lenX != 0 && lenY != 0) {//画斜线

            int disXu = (int) Math.round(Math.sqrt((Math.pow(lenY, 2) * Math.pow(lineLen, 2)) / (Math.pow(lenX, 2) + Math.pow(lenY, 2))));//x的步长
            int disXdu = (int) Math.round(Math.sqrt((Math.pow(lenY, 2) * Math.pow(disLen, 2)) / (Math.pow(lenX, 2) + Math.pow(lenY, 2))));//x的间隔步长
            int disYu = (int) Math.round(lenY * 1.0 * disXu / lenX);//y的步长
            int disYdu = (int) Math.round(lenY * 1.0 * disXdu / lenX);//y的间隔步长
            if (disXu == 0) {
                disXu = 1;
            }
            if (disXdu == 0) {
                disXdu = 1;
            }

            for (int disX = 0; disX <= lenX; disX += (disXu + disXdu)) {

                x2 = x1 + disXu;
                y2 = y1 + disYu;
                g.drawLine(x1, y1, x2, y2);

                x1 = x2 + disXdu;
                y1 = y2 + disYdu;
            }

        } else {//画横竖线

            if (lenX == 0) {//画横线

                for (int disY = 0; disY <= lenY; disY += (lineLen + disLen)) {

                    y2 = y1 + lineLen;
                    g.drawLine(x1, y1, x2, y2);

                    y1 = y2 + disLen;
                }

            } else {

                for (int disX = 0; disX <= lenX; disX += (lineLen + disLen)) {

                    x2 = x1 + lineLen;
                    g.drawLine(x1, y1, x2, y2);

                    x1 = x2 + disLen;
                }

            }

        }
        g.dispose();


        return bi;
    }

    /**
     * base64 编码转换为 BufferedImage
     *
     * @param base64
     * @return
     */
    public static BufferedImage base64ToBufferedImage(String base64) {

        base64 = base64.replace("data:image/png;base64,", "");

        try {
            byte[] bytes1 = Base64.decodeBase64(base64);
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
            return ImageIO.read(bais);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

    }

}
